import TinyPng from "tinypngjs";
import { existsSync, statSync, readFileSync, copyFileSync, writeFileSync, mkdirSync, readdirSync, unlinkSync, rmdirSync } from "fs";
import { join, extname, dirname } from "path";
import { createHash } from "crypto";
import { getAllImgs } from "../utils/FileUtil";

var cacheHash: { [path: string]: string } = {};
var cacheHead = join(__dirname, '../../cache')
var cacheJsonUrl = join(cacheHead, 'cache.json');
var crtTime = 0;

export function clearAllCache() {
    let cacheUrl = join(cacheHead);
    delDir(cacheUrl);
    console.log('clear over');
}

function delDir(dirPath: string) {
    if (!existsSync(dirPath)) return;
    try {
        let stat = statSync(dirPath)
        if (stat.isDirectory()) {
            let files = readdirSync(dirPath);
            files.forEach(f => {
                let ifurl = join(dirPath, f)
                if (statSync(ifurl).isDirectory()) {
                    delDir(ifurl);
                } else {
                    unlinkSync(ifurl);
                }
            })
            rmdirSync(dirPath);
        } else if (stat.isFile()) {
            unlinkSync(dirPath);
        }
    } catch (e) {
        console.log(e)
    }
}

function readCacheData() {
    if (!existsSync(cacheJsonUrl)) {
        cacheHash = {};
        return;
    }
    cacheHash = JSON.parse(readFileSync(cacheJsonUrl).toString());
}

function hashFile(filePath: string, fileData?: Buffer) {
    let md5 = createHash('md5');
    if (!fileData) {
        fileData = readFileSync(filePath);
    }
    md5.update(fileData);
    let md5Str = md5.digest('hex');
    return md5Str;
}

function createDirSync(dirPath: string, callback?: () => void) {
    if (existsSync(dirPath)) {
        if (!!callback) {
            callback();
        }
    } else {
        createDirSync(dirname(dirPath), () => {
            mkdirSync(dirPath);
            if (!!callback) {
                callback();
            }
        });
    }
}

/**
 * 压缩
 * @param path 需要压缩的路径，可以是文件夹路径，也可以是文件路径
 * @param out 压缩后的导出路径，可以是文件夹路径，也可以是文件路径
 */
export async function compress(path: string | { path: string }[], out?: string | { path: string }[], showComplete = true) {
    if (!out) out = path;

    crtTime = Date.now();
    readCacheData();

    if (typeof path == 'string') {
        if (!existsSync(path)) {
            console.log('no such file or dir');
            return;
        }
        try {
            if (statSync(path).isFile()) {
                console.log('开始压缩图片==>', path);

                let str = hashFile(path);
                let cacheImgUrl = '';// join(cacheHead, str + extname(path));

                let compressedName = cacheHash[str];
                let hasCompressed = false;
                for (let key in cacheHash) {
                    let temp = cacheHash[key];
                    if (temp == str) {
                        hasCompressed = true;// 之前被压缩过的
                        break;
                    }
                }
                if (compressedName) {
                    // 当前的源图片的内容hash，在缓存中有对应的压缩过的文件hash
                    cacheImgUrl = join(cacheHead, compressedName + extname(path));

                    // 如果要压缩的文件，在缓存中已经存在过了，且没改变，则将cache中缓存的图片直接拷贝到out中
                    if (typeof out == 'string' && existsSync(cacheImgUrl)) {
                        copyFileSync(cacheImgUrl, out);
                        if (showComplete) complete();
                        console.log('use time:', Date.now() - crtTime + 'ms');
                        return;
                    }
                } else if (hasCompressed) {
                    // 当前的图片已经是被压缩过的，且本地也有这个被压缩过的图片，则将cache中缓存的图片直接拷贝到out中
                    cacheImgUrl = join(cacheHead, str + extname(path));
                    if (typeof out == 'string' && existsSync(cacheImgUrl)) {
                        copyFileSync(cacheImgUrl, out);
                        if (showComplete) complete();
                        console.log('use time:', Date.now() - crtTime + 'ms');
                        return;
                    }
                }

                await TinyPng.compressImg(path, out).then(() => {
                    if (typeof out == 'string') {
                        createDirSync(join(cacheHead));
                        let compressedName = hashFile(out);
                        cacheImgUrl = join(cacheHead, compressedName + extname(path));
                        copyFileSync(out, cacheImgUrl);
                        cacheHash[str] = compressedName;
                        saveJson()
                        if (showComplete) complete();
                    } else {
                        console.log('out path error');
                    }
                }).catch(e => {
                    cacheHash[str] = '';
                    console.log(e);
                })
            } else {
                let files = [];
                getAllImgs(path, files);
                // let files = await TinyPng.getAllImg(path);
                // console.log('!!~~\n', files);
                for (let i = 0; i < files.length; i++) {
                    const url = files[i];
                    await compress(url, url, false);
                    if (i + 1 >= files.length) {
                        complete();
                    }
                }

                /* return;
                await TinyPng.compress(path, out, (res, p) => {
                    console.log(res);
                    if (p == 1) {
                        complete()
                    }
                }) */
            }
        } catch (e) {
            console.log(e);
        }
    } else {

        for (let i = 0; i < path.length; i++) {
            const url = path[i].path;
            await compress(url, url, false);
            if (i + 1 >= path.length) {
                complete();
            }
        }

    }
}

function saveJson() {
    let str = JSON.stringify(cacheHash);
    writeFileSync(cacheJsonUrl, str);

    console.log('use time:', Date.now() - crtTime + 'ms');

}

function complete() {

    console.log('+------------------------+');
    console.log('|    compress finish!    |');
    console.log('+------------------------+\n');

}